import java.util.ArrayList;
import java.util.List;

import com.smartxls.WorkBook;

public class Behavior {

	private int populationSize = 100;
	private double startReputation = 0.5;
	private double cost = 5;
	private double benefit = 10;
	private int historySize = 0;
	private ArrayList<Agent> agentList = new ArrayList<Agent>();

	public Behavior(int populationSize, double startReputation, double cost,
			double benefit, int historySize) {
		this.populationSize = populationSize;
		this.startReputation = startReputation+((Math.random()*0.1)+0.45);
		this.cost = cost;
		this.benefit = benefit;
		this.historySize = historySize;

		initialize();
	}

	private void initialize() {
		// Constructing Agent objects, with different attributes, and adding them to the List.
		int tmpSize = populationSize/9;
		
		for (int i=0 ; i < tmpSize ; i++)
			agentList.add(new Agent(0.1, historySize));
		for (int i=tmpSize ; i < tmpSize*2 ; i++)
			agentList.add(new Agent(0.2, historySize));
		for (int i=tmpSize*2 ; i < tmpSize*3 ; i++)
			agentList.add(new Agent(0.3, historySize));
		for (int i=tmpSize*3 ; i < tmpSize*4 ; i++)
			agentList.add(new Agent(0.4, historySize));
		for (int i=tmpSize*4 ; i < tmpSize*5 ; i++)
			agentList.add(new Agent(0.5, historySize));
		for (int i=tmpSize*5 ; i < tmpSize*6 ; i++)
			agentList.add(new Agent(0.6, historySize));
		for (int i=tmpSize*6 ; i < tmpSize*7 ; i++)
			agentList.add(new Agent(0.7, historySize));
		for (int i=tmpSize*7 ; i < tmpSize*8 ; i++)
			agentList.add(new Agent(0.8, historySize));
		for (int i=tmpSize*8 ; i < tmpSize*9 ; i++)
			agentList.add(new Agent(0.9, historySize));
	}

	public void interactPrisoners(double groupSize, double benefitThreshold) {
		// Agents interact in the prisoners dilemma game.
		double repetition = agentList.size() / groupSize;

		for (int u = 0; u < repetition; u++) {
			ArrayList<Agent> l = new ArrayList<Agent>();

			for (int i = 0; i < groupSize; i++) {
				l.add(getRandomAgent());
			}

			// Calculates whether the group is granted a reward.
			int coopNum = 0;
			for (Agent a : l) { // l is a list/collection from which all a are taken exactly once
				List<Agent> tmpList = l;
				tmpList.remove(a);
				if (a.determineStragedy(tmpList) == StrategyType.cooperator) {
					a.pay(cost);
					a.history.Push(StrategyType.cooperator);
					coopNum++;
				}
				else {
					a.history.Push(StrategyType.defector);
				}
			}

			// Agents receive their reward.
			if (coopNum >= benefitThreshold) {
				reward(l);
			}
		}
	}
	
	public void printToXLS(WorkBook wb, int generation, int generations) {
		double fit00 = 0, fit01 = 0, fit02 = 0, fit03 = 0, fit04 = 0, fit05 = 0, fit06 = 0, fit07 = 0, fit08 = 0, fit09 = 0, fit10 = 0;
		double count00 = 0, count01 = 0, count02 = 0, count03 = 0, count04 = 0, count05 = 0, count06 = 0, count07 = 0, count08 = 0, count09 = 0, count10 = 0;
		
		for (Agent a : agentList) {
			if(a.threshold == 0.0) {
				fit00 += a.getReputation();
				count00++;
			}
			if(a.threshold == 0.1) {
				fit01 += a.getReputation();
				count01++;
			}
			if(a.threshold == 0.2) {
				fit02 += a.getReputation();
				count02++;
			}
			if(a.threshold == 0.3) {
				fit03 += a.getReputation();
				count03++;
			}
			if(a.threshold == 0.4) {
				fit04 += a.getReputation();
				count04++;
			}
			if(a.threshold == 0.5) {
				fit05 += a.getReputation();
				count05++;
			}
			if(a.threshold == 0.6) {
				fit06 += a.getReputation();
				count06++;
			}
			if(a.threshold == 0.7) {
				fit07 += a.getReputation();
				count07++;
			}
			if(a.threshold == 0.8) {
				fit08 += a.getReputation();
				count08++;
			}
			if(a.threshold == 0.9) {
				fit09 += a.getReputation();
				count09++;
			}
			if(a.threshold == 1.0) {
				fit10 += a.getReputation();
				count10++;
			}
			
		}
		try {
			wb.setText(0, 0, "Threshold/Generation");
			for(int i = 0 ; i < 11 ; i++)
				wb.setNumber(i+1, 0, i*10);
			for(int i = 0 ; i < generations+1 ; i++)
				wb.setNumber(0, i+1, i);
			
			wb.setNumber(1, generation+1, fit00/count00);
			wb.setNumber(2, generation+1, fit01/count01);
			wb.setNumber(3, generation+1, fit02/count02);
			wb.setNumber(4, generation+1, fit03/count03);
			wb.setNumber(5, generation+1, fit04/count04);
			wb.setNumber(6, generation+1, fit05/count05);
			wb.setNumber(7, generation+1, fit06/count06);
			wb.setNumber(8, generation+1, fit07/count07);
			wb.setNumber(9, generation+1, fit08/count08);
			wb.setNumber(10, generation+1, fit09/count00);
			wb.setNumber(11, generation+1, fit10/count10);
			
			wb.write("./test.xls");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void printToConsole(int generation) {		
		double fit00 = 0, fit01 = 0, fit02 = 0, fit03 = 0, fit04 = 0, fit05 = 0, fit06 = 0, fit07 = 0, fit08 = 0, fit09 = 0, fit10 = 0;
		double count00 = 0, count01 = 0, count02 = 0, count03 = 0, count04 = 0, count05 = 0, count06 = 0, count07 = 0, count08 = 0, count09 = 0, count10 = 0;
		
		for (Agent a : agentList) {
			if(a.threshold == 0.0) {
				fit00 += a.getReputation();
				count00++;
			}
			if(a.threshold == 0.1) {
				fit01 += a.getReputation();
				count01++;
			}
			if(a.threshold == 0.2) {
				fit02 += a.getReputation();
				count02++;
			}
			if(a.threshold == 0.3) {
				fit03 += a.getReputation();
				count03++;
			}
			if(a.threshold == 0.4) {
				fit04 += a.getReputation();
				count04++;
			}
			if(a.threshold == 0.5) {
				fit05 += a.getReputation();
				count05++;
			}
			if(a.threshold == 0.6) {
				fit06 += a.getReputation();
				count06++;
			}
			if(a.threshold == 0.7) {
				fit07 += a.getReputation();
				count07++;
			}
			if(a.threshold == 0.8) {
				fit08 += a.getReputation();
				count08++;
			}
			if(a.threshold == 0.9) {
				fit09 += a.getReputation();
				count09++;
			}
			if(a.threshold == 1.0) {
				fit10 += a.getReputation();
				count10++;
			}
			
		}
		System.out.println("*** Generation " + generation + " ***");
		System.out.println("Agerage reputation for agents with threshold 0.1: " + fit01/count01 + ".");
		System.out.println("Agerage reputation for agents with threshold 0.2: " + fit02/count02 + ".");
		System.out.println("Agerage reputation for agents with threshold 0.3: " + fit03/count03 + ".");
		System.out.println("Agerage reputation for agents with threshold 0.4: " + fit04/count04 + ".");
		System.out.println("Agerage reputation for agents with threshold 0.5: " + fit05/count05 + ".");
		System.out.println("Agerage reputation for agents with threshold 0.6: " + fit06/count06 + ".");
		System.out.println("Agerage reputation for agents with threshold 0.7: " + fit07/count07 + ".");
		System.out.println("Agerage reputation for agents with threshold 0.8: " + fit08/count08 + ".");
		System.out.println("Agerage reputation for agents with threshold 0.9: " + fit09/count09 + ".");
		System.out.println("-");
		
		double avgRep = 0;
		double count = 0;
		for (Agent a : agentList) {
			avgRep += a.getReputation();
			count++;
		}
		avgRep /= count;
		
		System.out.println("The average reputation of the population:         " + avgRep + ".\n");
	}

	private Agent getRandomAgent() {
		return agentList.get((int) (agentList.size() * Math.random()));
	}

	private void reward(ArrayList<Agent> agentList) {
		for (Agent a : agentList) {
			a.reward(benefit);
		}
	}
	
	public void printAll(int generation) {
		System.out.println("*** Generation " + generation + " ***");
		for (Agent a : agentList) {
			System.out.println("Rep for agent: " + a.getReputation());
		}
		System.out.println();
	}
}